#include "main.h"

static struct shm_param para; // 共享内存参数
struct sockaddr_in sock_t, sock_c;
ipport_t tmip; // 初始化结构体
char path[128] = "/home/hq/";
char md5_cmd[128] = ""; // MD5命令缓冲区
fileinfo_t file_update; // 文件更新信息
int unzip_status = 1;

/**
 * @brief 读取配置文件并赋值给结构体
 * @return 成功返回0，失败返回-1
 */
int assignment() // 解析JSON文件，实例化到结构体中
{
    char json[2048] = "";
    FILE *fp = fopen(_PATH, "r"); // 创建文件指针
    if (fp == NULL)
    {
        perror("err: fopen");
        return -1;
    }

    int n = fread(json, 1, sizeof(json), fp); // 读取文件内容
    if (n < 0)
    {
        perror("err: fread");
        fclose(fp);
        return -1;
    }

    cJSON *root = cJSON_Parse(json); // 解析JSON数据
    if (root == NULL)
    {
        printf("Failed to parse JSON-------1.\n");
        fclose(fp);
        return -1;
    }
    cJSON *ver = cJSON_GetObjectItem(root, "version");
    if (ver == NULL)
    {
        printf("Failed to get 'version' from JSON.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    strncpy(tmip.version, ver->valuestring, sizeof(ver->valuestring) - 1); // 复制版本号

    cJSON *tcpip = cJSON_GetObjectItem(root, "tcp_server"); // 获取"tcp_server"字段
    if (tcpip == NULL)
    {
        printf("Failed to get 'tcp_server' from JSON.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    cJSON *tcp_addr = cJSON_GetObjectItem(tcpip, "addr"); // 获取"addr"字段
    cJSON *tcp_port = cJSON_GetObjectItem(tcpip, "port"); // 获取"port"字段
    if (tcp_addr == NULL || tcp_port == NULL)
    {
        printf("Failed to get tcp_addr or tcp_port.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    strncpy(tmip.tcp_ip, tcp_addr->valuestring, sizeof(tmip.tcp_ip) - 1);
    tmip.tcp_ip[sizeof(tmip.tcp_ip) - 1] = '\0';
    tmip.tcp_port = tcp_port->valueint;

    cJSON *mqttip = cJSON_GetObjectItem(root, "mqtt_server"); // 获取"mqtt_server"字段
    if (mqttip == NULL)
    {
        printf("Failed to get 'mqtt_server' from JSON.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }

    cJSON *mqtt_addr = cJSON_GetObjectItem(mqttip, "addr"); // 获取"addr"字段
    cJSON *mqtt_port = cJSON_GetObjectItem(mqttip, "port"); // 获取"port"字段
    if (mqtt_addr == NULL || mqtt_port == NULL)
    {
        printf("Failed to get mqtt_addr or mqtt_port.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    strncpy(tmip.mqtt_ip, mqtt_addr->valuestring, sizeof(tmip.mqtt_ip) - 1);
    tmip.mqtt_ip[sizeof(tmip.mqtt_ip) - 1] = '\0';
    tmip.mqtt_port = mqtt_port->valueint;

    cJSON_Delete(root); // 正确释放整个JSON树
    fclose(fp);         // 关闭文件指针
    return 0;
}

/**
 * @brief 主函数
 * @param argc
 * @param argv
 * @return
 */
int main(int argc, char const *argv[])
{
    int ac_fd;
    sqlite3 *db;
    char *errmsg = NULL;
    if (sqlite3_open(user_db_path, &db) != SQLITE_OK) // 打开数据库
    {
        fprintf(stderr, "Database open : %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 创建表
    const char *create_table_sql = "CREATE TABLE IF NOT EXISTS user_manage ("
                                   "account TEXT PRIMARY KEY, "
                                   "password TEXT)";

    if (sqlite3_exec(db, create_table_sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "Create table error: %s\n", errmsg);
        sqlite3_free(errmsg);
        sqlite3_close(db);
        return -1;
    }

    int udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
    int tcp_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (udp_fd < 0 || tcp_fd < 0)
    {
        perror("err: socket");
        return -1;
    }

    if (assignment() != 0) // 进行资源分配
    {
        printf("Assignment failed.\n");
        close(udp_fd);
        return -1;
    }

    socklen_t len = sizeof(sock_c);
    sock_t.sin_family = AF_INET;
    sock_t.sin_port = htons(main_port);  // 使用传入的端口
    sock_t.sin_addr.s_addr = INADDR_ANY; // 监听所有接口

    if (bind(udp_fd, (struct sockaddr *)&sock_t, sizeof(sock_t)) < 0)
    {
        perror("err: bind");
        close(udp_fd);
        return -1;
    }

    char buf[128] = "";
    while (1)
    {
        ssize_t n = recvfrom(udp_fd, buf, sizeof(buf), 0, (struct sockaddr *)&sock_c, &len); // 接收数据
        printf("ip: %s port: %d\n", inet_ntoa(sock_c.sin_addr), ntohs(sock_c.sin_port));     // 打印客户端IP和端口
        if (n < 0)
        {
            perror("err: recvfrom");
            close(udp_fd);
            return -1;
        }
        else if (n == 0)
        {
            printf("client exit\n");
            break;
        }
        else
        {
            buf[n] = '\0';                  // 确保字符串终止
            cJSON *root = cJSON_Parse(buf); // 解析JSON数据
            if (root == NULL)
            {
                printf("Failed to parse JSON----------2\n");
                continue; // 继续循环而不是退出
            }
            cJSON *type = cJSON_GetObjectItem(root, "type"); // 获取"type"字段
            if (type == NULL)
            {
                printf("Failed to get 'type' from JSON.\n");
                cJSON_Delete(root);
                continue;
            }
            cJSON *req = cJSON_GetObjectItem(root, "request"); // 获取"request"字段
            if (req == NULL)
            {
                printf("Failed to get 'request' from JSON.\n");
                cJSON_Delete(root);
                continue;
            }
            strcpy(tmip.request, req->valuestring);
            tmip.request[sizeof(tmip.request) - 1] = '\0';
            printf("type = %d\n", type->valueint);
            printf("request = %s\n", tmip.request);
            cJSON_Delete(root); // 正确释放整个JSON树
            break;
        }
    }
    if (strcmp(tmip.request, "connect_info") == 0) // 请求连接信息
    {
        cJSON *root = cJSON_CreateObject();
        cJSON_AddNumberToObject(root, "type", 0); // 添加"type"字段

        cJSON *data_obj = cJSON_CreateObject(); // 创建一个新的object对象
        cJSON_AddStringToObject(data_obj, "mqtt_address", tmip.mqtt_ip);
        cJSON_AddNumberToObject(data_obj, "mqtt_port", tmip.mqtt_port);
        cJSON_AddStringToObject(data_obj, "tcp_address", tmip.tcp_ip);
        cJSON_AddNumberToObject(data_obj, "tcp_port", tmip.tcp_port);

        cJSON_AddItemToObject(root, "data", data_obj); // 将"data"字段添加到根对象中

        char *json_data = cJSON_Print(root); // 将JSON对象转换为字符串
        if (json_data == NULL)
        {
            printf("Failed to print JSON.\n");
            cJSON_Delete(root);
            close(udp_fd);
            return -1;
        }
        printf("%s\n", json_data);                                                                    // 调试打印
        ssize_t n = sendto(udp_fd, json_data, strlen(json_data), 0, (struct sockaddr *)&sock_c, len); // 修复长度
        if (n < 0)
        {
            perror("err: sendto");
        }

        free(json_data); // 释放cJSON_Print分配的内存
        cJSON_Delete(root);
        close(udp_fd);
    }

    // TCP服务器部分
    printf("等待建立TCP连接...\n");                                   // TCP连接建立提示
    if (bind(tcp_fd, (struct sockaddr *)&sock_t, sizeof(sock_t)) < 0) // 绑定
    {
        perror("err: bind");
        close(tcp_fd);
        return -1;
    }

    if (listen(tcp_fd, 6) < 0) // 监听
    {
        perror("err: listen");
        return -1;
    }

    int optval = 1;
    setsockopt(tcp_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // 重用地址
    
    while (1)
    {
        // 在TCP服务器中,有两类文件描述符
        // 一类用于通信的文件描述符:可能有多个(accept函数返回值)
        // 一类用于连接的文件描述符:只有一个(socket函数返回值)
        if ((ac_fd = accept(tcp_fd, (struct sockaddr *)&sock_c, &len)) < 0) // 接受
        {
            perror("err: accept");
            return -1;
        }
        char buf[512] = "";
        while (1)
        {
            ssize_t r = recv(ac_fd, buf, sizeof(buf), 0); // 接收信息
            buf[strlen(buf)] = '\0';                      // 确保字符串终止
            if (r < 0)
            {
                perror("err: recv");
                return -1;
            }
            else if (r == 0)
            {
                printf("client exit\n");
                close(ac_fd);
                break;
            }
            else if (r > 0)
            {
                printf("client: %s\n", buf);
                file_handle(buf, ac_fd, db);
                memset(buf, 0, sizeof(buf));
            }
            if (strlen(file_update.md5) > 0)
            {
                // 检查文件更新
                cJSON *root = cJSON_CreateObject();
                if (!unzip_status)
                {
                    cJSON_AddItemToObject(root, "unzip", cJSON_CreateBool(TRUE));
                    char *final = cJSON_Print(root);
                    if (send(ac_fd, final, strlen(final), 0) < 0)
                    {
                        perror("err: send");
                        close(ac_fd);
                        return -1;
                    }
                    free(final);
                }
                else if (unzip_status < 0)
                {
                    cJSON_AddItemToObject(root, "unzip", cJSON_CreateBool(FALSE));
                    char *final = cJSON_Print(root);
                    if (send(ac_fd, final, strlen(final), 0) < 0)
                    {
                        perror("err: send");
                        close(ac_fd);
                        return -1;
                    }
                    free(final);
                }
                unzip_status = 1;
                memset(md5_cmd, 0, sizeof(md5_cmd));
                cJSON_Delete(root);
            }
        }
    }
    sqlite3_close(db);
    return 0;
}